package com.filldream.fastboot.core.service.impl;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.filldream.fastboot.base.entity.BaseParam;
import com.filldream.fastboot.base.mapper.BaseParamMapper;
import com.filldream.fastboot.base.request.common.baseParam.BaseParamListSTO;
import com.filldream.fastboot.base.request.pc.baseParam.BaseParamParentPageSTO;
import com.filldream.fastboot.common.entity.ErrorCode;
import com.filldream.fastboot.common.entity.P;
import com.filldream.fastboot.common.entity.R;
import com.filldream.fastboot.common.util.Assert;
import com.filldream.fastboot.core.LoginHolder;
import com.filldream.fastboot.core.manager.BaseParamManager;
import com.filldream.fastboot.core.service.BaseParamService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author:RickSun
 * @date:2019/1/16 0016
 * description:
 **/
@Service
@Transactional(rollbackFor = Exception.class)
public class BaseParamServiceImpl extends ServiceImpl<BaseParamMapper, BaseParam> implements BaseParamService {


    @Override
    public P<BaseParam> page(BaseParamParentPageSTO baseParamParentPageSTO) {
        QueryWrapper<BaseParam> sql = new QueryWrapper<>();
        sql.eq("param_type",baseParamParentPageSTO.getParamType());
        sql.orderByDesc("create_time");


        if(StringUtils.isNotEmpty(baseParamParentPageSTO.getParamCode())){
            sql.like("param_code", baseParamParentPageSTO.getParamCode() );
        }

        if(StringUtils.isNotEmpty(baseParamParentPageSTO.getParamValue())){
            sql.like("param_value",baseParamParentPageSTO.getParamValue());
        }

        if( baseParamParentPageSTO.getParentId() != null ){
            sql.eq("parent_id",baseParamParentPageSTO.getParentId());
        }

        if(StringUtils.isNotEmpty(baseParamParentPageSTO.getParamKey())){
            sql.like("param_key",baseParamParentPageSTO.getParamKey());
        }

        if( baseParamParentPageSTO.getParamType().equals(2) && !LoginHolder.getPcUser().getLinkId().equals(1L) ){
            sql.eq("link_id",LoginHolder.getPcUser().getLinkId());
        }

        Page<BaseParam> page = baseMapper.selectPage(baseParamParentPageSTO.page(), sql);

        return P.autoSuccess(page);
    }

    @Override
    public Boolean add(BaseParam baseParam){

        baseParam.setId(null);
        Assert.isEmpty( baseParam.getParentId(),"父级参数ID不能为空" );
        Assert.isBank( baseParam.getParamValue(),"参数值不能为空" );

        if( baseParam.getParentId() > 0 ){
            BaseParam parent = BaseParamManager.getById(baseParam.getParentId());
            Assert.isEmpty(parent,"父级参数不存在");
            baseParam.setParamCode(parent.getParamCode());
            baseParam.setParamType( parent.getParamType() );
            baseParam.setLinkId( parent.getLinkId() );
            Assert.isBank( baseParam.getParamKey(),"参数Key不能为空" );
        }else{
            baseParam.setParamKey( "-1" );
            baseParam.setLinkId(baseParam.getParamType().equals(2) ? LoginHolder.getPcUser().getLinkId() : 0L);
            Assert.isBank( baseParam.getParamCode(), "参数编号不能为空" );
        }


        checkCodeAndKeyAndValue(baseParam);


        baseParam.setCreateUser( LoginHolder.getPcUserId() );
        boolean insert = save(baseParam) ;

        //删除缓存
        if( insert ){
            BaseParamManager.delCacheListByCode( baseParam.getParamCode() );
        }
        return insert;
    }

    @Override
    public Boolean modify(BaseParam baseParam) {
        Long id = baseParam.getId();
        baseParam.setParentId(null);
        BaseParam oldParam = BaseParamManager.getById(id);
        String oldParamCode = oldParam.getParamCode();

        //修改父级参数的编号时同时修改所有子级参数
        if( oldParam.getParentId().equals(0L) ){
            baseParam.setParamKey("-1");
            baseParam.setParamType(oldParam.getParamType());
            if( !oldParamCode.equals(baseParam.getParamCode()) ){
                checkCodeAndKey(baseParam.getParamCode(),"-1",oldParam.getLinkId(),oldParam.getParamType());
                //查出所有的子级进行修改
                BaseParamListSTO baseParamListSTO = new BaseParamListSTO().setParamCode(oldParamCode).setIsContainParent(true);
                List<BaseParam> list = BaseParamManager.getListByCode(baseParamListSTO);
                List<Long> updateChildIds = list.stream().map(BaseParam::getId).collect(Collectors.toList());
                update(new BaseParam().setParamCode(baseParam.getParamCode()),new QueryWrapper<BaseParam>().in("id",updateChildIds));
                BaseParamManager.delCacheDetailByIds(updateChildIds);
                BaseParamManager.delCacheListByCode( oldParamCode );
            }
        }else{
            baseParam.setParamCode(oldParamCode);
            if( !oldParam.getParamKey().equals(baseParam.getParamKey()) ){
                checkCodeAndKey(baseParam.getParamCode(),baseParam.getParamKey(),oldParam.getLinkId(),oldParam.getParamType());
            }
        }
        baseParam.setUpdateUser( LoginHolder.getPcUserId() );
        updateById(baseParam);
        BaseParamManager.delCacheDetailById(baseParam.getId());
        BaseParamManager.delCacheListByCode( baseParam.getParamCode() );
        return true;
    }

    @Override
    public R<List<Tree<String>>> tree(Integer paramType) {
        if( paramType == null ){
            paramType = 1;
        }
        List<BaseParam> list = list(new LambdaQueryWrapper<BaseParam>().eq(BaseParam::getParamType, paramType).orderByDesc(BaseParam::getCreateTime));

        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setWeightKey("createTime");
        treeNodeConfig.setIdKey("id");
        treeNodeConfig.setChildrenKey("dataList");
        treeNodeConfig.setNameKey("paramValue");

        List<Tree<String>> treeNodes = TreeUtil.build(list, "0", treeNodeConfig,
                (treeNode, tree) -> {
                    tree.setId(treeNode.getId()+"");
                    tree.setParentId(treeNode.getParentId()+"");
                    tree.setWeight(treeNode.getCreateTime());
                    tree.setName(treeNode.getParamValue());

                    tree.putExtra("paramKey",treeNode.getParamKey());
                    tree.putExtra("paramValue",treeNode.getParamValue());
                    tree.putExtra("paramCode",treeNode.getParamCode());
                    tree.putExtra("tagType",treeNode.getTagType());

                });

        return R.successd(treeNodes);
    }


    //查询同样的code不允许出现同样的key
    public void checkCodeAndKey( String paramCode,String paramKey,Long linkId,Integer paramType ){
        BaseParamListSTO baseParamListSTO = new BaseParamListSTO();
        baseParamListSTO.setParamCode(paramCode);
        baseParamListSTO.setLinkId(linkId);
        baseParamListSTO.setParamType(paramType);
        baseParamListSTO.setIsContainParent(true);
        List<BaseParam> list = BaseParamManager.getListByCode(baseParamListSTO);
        if(ObjectUtils.isNotEmpty(list)){
            long count = list.stream().filter(item ->
                     item.getParamKey().equals(paramKey)
            ).count();
            Assert.checkBoolean( count < 1, ErrorCode.BASE_ERR.reMsg("请勿添加重复参数"));
        }
    }

    //查询同样的code不允许出现同样的key
    public void checkCodeAndKeyAndValue( BaseParam baseParam ){
        BaseParamListSTO baseParamListSTO = new BaseParamListSTO();
        baseParamListSTO.setParamCode(baseParam.getParamCode());
        baseParamListSTO.setLinkId(baseParam.getLinkId());
        baseParamListSTO.setParamType(baseParam.getParamType());
        baseParamListSTO.setIsContainParent(true);
        List<BaseParam> list = BaseParamManager.getListByCode(baseParamListSTO);
        if(ObjectUtils.isNotEmpty(list)){
            long count = list.stream().filter(item ->
                    baseParam.getParentId() > 0L ? item.getParamValue().equals(baseParam.getParamValue()) : item.getParamKey().equals(baseParam.getParamKey())
            ).count();
            Assert.checkBoolean( count < 1, ErrorCode.BASE_ERR.reMsg("请勿添加重复参数"));
        }
    }


}
